Skip to content

[MAINTAINED-EXTERNALLY] leds: rgb: add leds-valve driver#81

Merged
KyleGospo merged 84 commits into
OpenGamingCollective:features/steammachinefrom
mdeneen:ogc-7.1.y
Jul 21, 2026
Merged

[MAINTAINED-EXTERNALLY] leds: rgb: add leds-valve driver#81
KyleGospo merged 84 commits into
OpenGamingCollective:features/steammachinefrom
mdeneen:ogc-7.1.y

Conversation

@mdeneen

@mdeneen mdeneen commented Jul 15, 2026

Copy link
Copy Markdown

Add initial support for Valve LED strip on Valve Fremont (2026 Steam Machine)

Signed-off-by: Robert Beckett bob.beckett@collabora.com
Signed-off-by: Mark Deneen mdeneen@gmail.com

Ghoul4500 and others added 30 commits July 8, 2026 15:54
…an curve

On models flagged with requires_fan_curve in the DMI power_data table
(30 entries), the BIOS ACPI method SPLX only writes PPT values to the
EC when the fan mode is set to Manual (FANM=4). FANM is set to 4 by
the DEFC method when a custom fan curve is written. Without an active
custom fan curve, the WMI DEVS call returns success but the firmware
silently ignores the PPT value, so userspace observes no effect from
its write.

Gate writes to ASUS_WMI_DEVID_PPT_{PL1_SPL,PL2_SPPT,PL3_FPPT,APU_SPPT,
PLAT_SPPT} on a check of asus_wmi_custom_fan_curve_is_enabled(), and
return -EBUSY with a pr_warn_once() when no fan curve is active on an
affected model. Export the helper from asus-wmi so asus-armoury can
call it across module boundaries.

Signed-off-by: Ahmed Yaseen <yaseen@ghoul.dev>
Adds basic support for the joystick RGB LED rings as a multicolour LED
device with 4 LEDs. As this uses the software-mode for setting the LED
colours it also sets the MCU-mode for LED's to static + the first RGB
colour on suspend/reboot/shutdown. This is done to prevent user confusion
if the LED's were to not match what was set, and to maintain consistency.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
Export the validate_mcu_fw_version() symbol in namespace and use in
hid-asus-ally if the driver is enabled.

Signed-off-by: Luke Jones <luke@ljones.dev>
Enable use of the new gamepad device created by the MCU.
- Triggers
- Buttons
- Sticks
- Vibration

Signed-off-by: Luke D. Jones <luke@ljones.dev>
Add the basics of the gamepad configuration options. Makes the gamepad
usable.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
Add the full set of button remapping abilities for plain remap and macro
remap (hold one button, press another for macro mapped action).

Signed-off-by: Luke D. Jones <luke@ljones.dev>
Signed-off-by: Luke D. Jones <luke@ljones.dev>
Signed-off-by: Luke D. Jones <luke@ljones.dev>
Signed-off-by: Luke D. Jones <luke@ljones.dev>
Signed-off-by: Luke D. Jones <luke@ljones.dev>
Signed-off-by: Luke D. Jones <luke@ljones.dev>
Signed-off-by: Luke D. Jones <luke@ljones.dev>
Add the mcu_version sysfs attribute so that userspace has a way to check
the MCU FW version.

Signed-off-by: Luke Jones <luke@ljones.dev>
Signed-off-by: Luke D. Jones <luke@ljones.dev>
The hid report for the QAM button changed on the ASUS ROG Xbox Ally X,
so add the new mapping for the short press event. Otherwise, all we get
is a long press event on "Asus Keyboard".

neptune:
We're carrying this as [NOT-FOR-UPSTREAM] because the last version of
hid-asus-ally on lkml was in August of 2024, and we have some divergence
from the last submission upstream. This should be included upstream when
there is a new submission for hid-asus-ally.

Reviewed-by: Derek J. Clark <derekjohn.clark@gmail.com>
Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
With the current ROG Ally patchset, the MCU will send spurious events
when the ROG Ally is in s2idle while plugged in, which can cause the
system to wake unexpectedly.

There's really no reason the N-Key needs wakeup enabled, so just
disable the capability for now. This can be dropped when the issue is
root caused and fixed within the standard ROG Ally patchset.

Closes: ValveSoftware/SteamOS#2119
Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
Adds platform driver for AYN Loki and Tectoy Zeenix lines of handheld
devices. This patch implements a hwmon interface for EC provided manual
PWM fan control and user defined fan curves. A global ACPI lock is used
when reading or writing from the EC.

There are 4 fan modes implemented in this patch. Modes 0-3 act in
accordance with the standard hwmon logic where 0 is 100% fan speed, 1 is
manual control, and 2 is automatic control. As the EC only provides 3
modes by default, mode 0 is implemented by setting the device to manual
and then setting fan speed to 100% directly. In mode 1 the PWM duty cycle
is set in sysfs with values [0-255], which are then scaled to the EC max
of 128. Mode 4 is an automatic mode where the fan curve is user defined.
There are 5 total set points and each set point takes a temperature in
Celsius [0-100] and a PWM duty cycle [0-255]. When the CPU temperature
reaches a given set point, the corresponding duty cycle is automatically
set by the EC.

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds temperature sensors to the ayn-ec hwmon interface. These read-only
values include Battery, Motherboard, Charger IC, vCore, and CPU Core, as
well as labels for each entry. The temperature values provided by the EC
are whole numbers in degrees Celsius. As hwmon expects millidegrees, we
scale the raw value up.

`sensors` output after this patch is applied:
aynec-isa-0000
Adapter: ISA adapter
fan1:        1876 RPM
Battery:      +29.0°C
Motherboard:  +30.0°C
Charger IC:   +30.0°C
vCore:        +36.0°C
CPU Core:     +48.0°C

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds an EC controlled LED Multicolor Class Device for controlling the
RGB rings around the joysticks.

The EC provides a single register for each of the colors red, green, and
blue, as well as a mode switching register. The EC accepts values
[0-255] for all colors. There are two available effects: breathe, which is
the default when the device is started, and monocolor. When resuming from
sleep the user selected effect will be overwritten by the EC, so the
driver retains the last setting and resets on resume. When setting a
color, each color register is set before a final "write" code is sent to
the device. The EC may briefly reflect the "write" code when writing, but
quickly changes to the "monocolor" value once complete. The driver
interprets both of these values as "monocolor" in _show to simplify the
sysfs exposed to the user.

Two custom attributes are added to the standard LED parent device:
effect, a RW file descriptor used to set the effect, and effect_index,
which enumerates the available valid options.

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds ABI documentation for the ayn-ec platform driver

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Callers can use this feedback to be more aggressive in making space for
allocations of a cgroup if they know it is protected.

These are counterparts to memcg's mem_cgroup_below_{min,low}.

Signed-off-by: Natalie Vock <natalie.vock@gmx.de>
This helps to find a common subtree of two resources, which is important
when determining whether it's helpful to evict one resource in favor of
another.

To facilitate this, add a common helper to find the ancestor of two
cgroups using each cgroup's ancestor array.

Signed-off-by: Natalie Vock <natalie.vock@gmx.de>
Move all code for attempting allocation for a specific place to
ttm_bo_alloc_place. With subsequent patches, this logic is going to get
more complicated, so it helps readability to have this separate.

ttm_bo_alloc_at_place takes a pointer to a struct ttm_bo_alloc_state.
This struct holds various state produced by the allocation (e.g. cgroup
resource associated with the allocation) that the caller needs to keep
track of (and potentially dispose of). This is just the limiting cgroup
pool for now, but future patches will add more state needing to be tracked.

ttm_bo_alloc_at_place also communicates via return codes if eviction
using ttm_bo_evict_alloc should be attempted. This is preparation for
attempting eviction in more cases than just force_space being set.

No functional change intended.

Signed-off-by: Natalie Vock <natalie.vock@gmx.de>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Coupling resource allocation and cgroup charging is racy when charging
succeeds, but subsequent resource allocation fails. Certain eviction
decisions are made on the basis of whether the allocating cgroup is
protected, i.e. within its min/low limits, but with the charge being
tied to resource allocation (and uncharged when the resource allocation
fails), this check is done at a point where the allocation is not actually
charged to the cgroup.

This is subtly wrong if the allocation were to cause the cgroup to exceed
the min/low protection, but it's even more wrong if the same cgroup tries
allocating multiple buffers concurrently: In this case, the min/low
protection may pass for all allocation attempts when the real min/low
protection covers only some, or potentially none of the allocated
buffers.

Instead, charge the allocation to the cgroup once and keep the charge
for as long as we try to allocate a ttm_resource, and only undo the charge
if allocating the resource is ultimately unsuccessful and we move on to
a different ttm_place.

Signed-off-by: Natalie Vock <natalie.vock@gmx.de>
…n limit

When the cgroup's memory usage is below the low/min limit and allocation
fails, try evicting some unprotected buffers to make space. Otherwise,
application buffers may be forced to go into GTT even though usage is
below the corresponding low/min limit, if other applications filled VRAM
with their allocations first.

Signed-off-by: Natalie Vock <natalie.vock@gmx.de>
…t pool

When checking whether to skip certain buffers because they're protected
by dmem.low, we're checking the effective protection of the evictee's
cgroup, but depending on how the evictor's cgroup relates to the
evictee's, the semantics of effective protection values change.

When testing against cgroups from different subtrees, page_counter's
recursive protection propagates memory protection afforded to a parent
down to the child cgroups, even if the children were not explicitly
protected. This prevents cgroups whose parents were afforded no
protection from stealing memory from cgroups whose parents were afforded
more protection, without users having to explicitly propagate this
protection.

However, if we always calculate protection from the root cgroup, this
breaks prioritization of sibling cgroups: If one cgroup was explicitly
protected and its siblings were not, the protected cgroup should get
higher priority, i.e. the protected cgroup should be able to steal from
unprotected siblings. This only works if we restrict the protection
calculation to the subtree shared by evictor and evictee.

Signed-off-by: Natalie Vock <natalie.vock@gmx.de>
…n via dmem cgroups. Let

nouveau benefit from this as well by registering the vram region with
the dmem cgroup controller.

This patch adapts the approach amdgpu and Xe have taken for enabling
dmem cgroups.

Signed-off-by: Natalie Vock <natalie.vock@gmx.de>
…ributes

Use an enum for all device ID's and CPU attribute feature ID's,
add missing CPU attributes.

Reviewed-by: Rong Zhang <i@rong.moe>
Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
pastaq and others added 22 commits July 8, 2026 15:59
Adds intensity adjustment for the left and right rumble motors.

Claude was used during the reverse-engineering data gathering for this
feature done by Zhouwang Huang. As the code had already been affected,
I used Claude to create the initial framing for the feature, then did
manual cleanup of the _show and _store functions afterwards to fix bugs
and keep the coding style consistent. Claude was also used as an initial
reviewer of this patch.

Assisted-by: Claude:claude-sonnet-4-6
Co-developed-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Zhouwang Huang <honjow311@gmail.com>
Link: https://lore.kernel.org/r/20260516042841.500299-5-derekjohn.clark@gmail.com
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds OneXPlayer HID configuration driver. In this initial driver patch,
add the RGB interface for the first generation of HID based RGB control.

This interface provides the following attributes:
- brightness: provided by the LED core, this works in a fairly unique
  way on this device. The hardware accepts 5 brightness values (0-4),
  which affects the brightness of the multicolor and animated effects
  built into the MCU firmware. For monocolor settings, the device
  expects the hardware brightness value to be pushed to maximum, then we
  apply brightness adjustments mathematically based on % (0-100). This
  leads to some odd conversion as we need the brightness slider to reach
  the full range, but it has no affect when incrementing between the
  division points for other effects.
- multi-intensity: provided by the LED core for red, green, and blue.
- effect: Allows the MCU to set 19 individual effects.
- effect_index: Lists the 19 valid effect names for the interface.
- enabled: Allows the MCU to toggle the RGB interface on/off.
- enabled_index: Lists the valid states for enabled.
- speed: Allows the MCU to set the animation rate for the various
  effects.
- speed_range: Lists the valid range of speed (0-9).

The MCU also has a few odd quirks that make sending multiple synchronous
events challenging. It will essentially freeze if it receives another
message before it has finished processing the last command. It also will
not reply if you wait on it using a completion. To get around this, we
do a 200ms sleep inside a work queue thread and debounce all but the most
recent message using a 50ms mod_delayed_work. This will cache the last
write, queue the work, then return so userspace can release its write
thread. The work queue is only used for brightness/multi-intensity as
that is the path likely to receive rapid successive writes.

Reviewed-by: Zhouwang Huang <honjow311@gmail.com>
Tested-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds support for the second generation of RGB Control for OneXPlayer
devices. The interface mirrors the first generation, with some
differences to how messages are formatted.

Some devices have both a GEN1 MCU for RGB control and a GEN2 MCU for
button mapping. To avoid conflicts, quirk these devices to skip RGB
setup for the GEN2_USAGE_PAGE.

Reviewed-by: Zhouwang Huang <honjow311@gmail.com>
Tested-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds "gamepad_mode" attribute to second generation OneXPlayer
configuration HID devices. This attribute initiates a mode shift in the
device MCU that puts it into a state where all events are routed to an
hidraw interface instead of the xpad evdev interface. This allows for
debugging the hardware input mapping added in the next patch.

Reviewed-by: Zhouwang Huang <honjow311@gmail.com>
Tested-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds button mapping interface for second generation OneXPlayer
configuration HID interfaces. This interface allows the MCU to swap
button mappings at the hardware level. The current state cannot be
retrieved, and the mappings may have been modified in Windows prior, so
we reset the button mapping at init and expose an attribute to allow
userspace to do this again at any time.

The interface requires two pages of button mapping data to be sent
before the settings will take place. Since the MCU requires a 200ms
delay after each message (total 400ms for these attributes) use the same
debounce work queue method we used for RGB. This will allow for
userspace or udev rules to rapidly map all buttons. The values will
be cached before the final write is finally sent to the device.

Reviewed-by: Zhouwang Huang <honjow311@gmail.com>
Tested-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds attribute for setting the rumble intensity level. This setting must
be re-applied after the gamepad mode is set as doing so resets this to
the default value.

Reviewed-by: Zhouwang Huang <honjow311@gmail.com>
Tested-by: Zhouwang Huang <honjow311@gmail.com>
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
 Deck

Add MFD core driver for Steam Deck. Doesn't really do much so far
besides instantiating a number of MFD cells that implement all the
interesting functionality.

(cherry picked from commit 5f534c2d6ebdefccb9c024eb0f013bc1c0c622d9)
[fwd-ported to v6.11 and v7.0]
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Marco Rodolfi <marco.rodolfi@tuta.io>
 board power in sysfs

As of version 118 Deck's BIOS implements "SCBP" method that allows
gating power of the controller board (VBUS). Add a basic WO method to
our root MFD device to allow toggling that.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
(cherry picked from commit f97f32718acc10cbb51fef925842392e80904d74)
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
 sensors

Add driver for sensors exposed by EC firmware on Steam Deck hardware.

(cherry picked from commit 6917aac77bee6185ae3920b936cdbe7876118c0b)
[fwd-ported to v7.0]
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Marco Rodolfi <marco.rodolfi@tuta.io>
 for max battery  level/rate

Add support for max battery level/charge rate attributes.

(cherry picked from commit 50af83e8fd75dc52221edd3fb6fd7a7f70c4d8a4)

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
…Steam Deck

(cherry picked from commit 3fddb71726d5b6040660b00fc0bb5319457a4d84)
Signed-off-by: Kyle Gospodnetich <me@kylegospodneti.ch>
[Why]
Chrontel CH7218 found in Ugreen DP -> HDMI 2.1 adapter (model 85564)
works perfectly with VRR after testing. VRR and FreeSync compatibility
is explicitly advertised as a feature so it's addition is a formality.

Support FreeSync info packet passthrough and "generic" HDMI VRR.

[How]
Add CH7218's ID to dm_helpers_is_vrr_pcon_allowed()

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4773

Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Add initial support for Valve LED strip on Valve Fremont (2026 Steam
Machine)

Signed-off-by: Robert Beckett bob.beckett@collabora.com
Signed-off-by: Mark Deneen mdeneen@gmail.com
@mdeneen

mdeneen commented Jul 15, 2026

Copy link
Copy Markdown
Author

With this driver, and some udev rules to set permissions, I have the RGB LED strip on the front of a 2026 Steam Machine working in Bazzite. Steam's Big Picture Mode works to control the LEDs once the knobs in /sys/class/leds are available to it.

@Leon-Swains

Copy link
Copy Markdown

I’ve actually been experimenting with reverse-engineering the Valve-leds in an attempt to expose a third party LED strip to the Steam client on Bazzite in order to enable the same controls on non-Steam Machine builds. While I’m fairly certain this is out of scope of PR, I just had a question for testing purposes. Does this match against the real Fremont hardware (specifically (ACPI/DMI/etc). Or is there a known way to instantiate this without the authentic Steam Machine LEDs. I’ve been trying to work with a 17 LED strip registers under the exact same name as the Steam Machine’s. Is love to build directly against this instead once I understand how the hardware-facing side is separated from the classdev registration.

Also I’m gappy to test on non-Fremont hardware and report back if that’s useful data points for the upstream submission.

@mdeneen

mdeneen commented Jul 17, 2026

Copy link
Copy Markdown
Author

Hey Leon,

This driver reads/writes the IO port space directly, so what you're trying to do would be difficult with this specific driver.

With that being said, I suspect that the Steam Client is just checking for the existence of /sys/class/leds/valve-led[*] and reading / writing the sysfs files there. As long as your naming conventions match what Valve has chosen, I would think that the Steam Client would happily use them. The only way to know is to try it out. :-)

You could make a dummy LED driver which emulates the /sys/class/leds interface exposed by this one to test it out before wiring up hardware.

@Leon-Swains

Copy link
Copy Markdown

Figured as much, I was already working on creating a dummy driver for nonexistent LEDs to see if Steam detected it. Really with there was official documentation or a steamOS-manager interface for this. Thanks for the help though.

@KyleGospo KyleGospo changed the title [FOR-UPSTREAM] leds: rgb: add leds-valve driver [MAINTAINED-EXTERNALLY] leds: rgb: add leds-valve driver Jul 21, 2026
@KyleGospo
KyleGospo changed the base branch from ogc-7.1.y to features/steammachine July 21, 2026 01:51
@KyleGospo
KyleGospo merged commit 5ab3a73 into OpenGamingCollective:features/steammachine Jul 21, 2026
@mdeneen

mdeneen commented Jul 21, 2026

Copy link
Copy Markdown
Author

Thanks for merging!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.